package com.xt.base.reflection;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class EspecialProperties {
	
	private Class clazz;
	private Class elementClazz = null;
	
	private Map<String, Object> properties;
	
	public EspecialProperties(Class clazz){
		this.clazz = clazz;
		this.properties = new HashMap<String, Object>();
		this.properties.put("this", new HashSet<String>());
	}
	
	public boolean isEmpty(){
		Set<String> properties = getProperties(),classes = getClazzes();
		return (properties == null || properties.isEmpty()) && (classes == null || classes.isEmpty());
	}
	
	public EspecialProperties add(EspecialProperties especialProperties){
		if(especialProperties != null &&(BaseReflector.classEquals(clazz, especialProperties.getClazz())|| 
				BaseReflector.isCollection(especialProperties.getClazz()))){
			Set<String> props = especialProperties.getProperties();
			if(props != null){
				boolean xed = especialProperties.changeClazz();
				for(String s:props)add(s);
				if(xed)especialProperties.changeClazz();
			}
			Set<String> newKeys = especialProperties.getClazzes();
			if(newKeys != null){
				for(String name: newKeys){
					Field field= BaseReflector.getFieldFromAssign(this.clazz,name);
					if(field != null){
						if(!this.properties.containsKey(name))
							this.properties.put(name, new EspecialProperties(field.getType()));
						((EspecialProperties)this.properties.get(name)).
							add(especialProperties.getEspecialProperties(name));
					} 
				}
			}
		}
		return this;
	}
	
	public EspecialProperties remove(EspecialProperties especialProperties){
		if(especialProperties != null && especialProperties.getClazz().equals(clazz)){
			Set<String> properties = especialProperties.getProperties();
			if(properties != null)
				for(String s:properties)remove(s);
			Set<String> newKeys = especialProperties.getClazzes();
			if(newKeys != null){
				for(String name:newKeys){
					if(!this.properties.containsKey(name))
						((EspecialProperties)this.properties.get(name)).
							remove(especialProperties.getEspecialProperties(name));
				}
			}
		}
		return this;
	}
	
	public EspecialProperties add(String[] properties){
		if(properties != null)
			for(String s:properties)add(s);
		return this;
	}
	
	public EspecialProperties remove(String[] properties){
		for(String s:properties)remove(s);
		return this;
	}
	
	@SuppressWarnings("unchecked")
	public EspecialProperties add(String property){
		int idx = property.indexOf(".");
		if(idx == -1 || BaseReflector.isCollection(this.clazz)){
			if("clazz".equals(property) || BaseReflector.isCollection(this.clazz)|| 
					BaseReflector.getFieldFromAssign(this.clazz,property)!= null || 
					(this.clazz.isInterface() && BaseReflector.hasGetMethod(clazz, property))){
				if(!this.properties.containsKey("this"))this.properties.put("this", new HashSet());
				((Set<String>)this.properties.get("this")).add(property);
			}
		}else {
			String sub = property.substring(0,idx);
			String prop = property.substring(idx+1, property.length());
			Field field= BaseReflector.getFieldFromAssign(this.clazz,sub);
			if(field != null){
				if(!this.properties.containsKey(sub))
					this.properties.put(sub, new EspecialProperties(field.getType()));
				((EspecialProperties)this.properties.get(sub)).add(prop);
			}
		}
		return this;
	}
	
	public EspecialProperties remove(String property){
		int idx = property.indexOf(".");
		if(idx == -1 ){
			if("clazz".equals(property) || BaseReflector.getFieldFromAssign(this.clazz,property)!= null){
				if(this.properties.containsKey("this"))	((Set)this.properties.get("this")).remove(property);
			}
		}else {
			String sub = property.substring(0,idx);
			String prop = property.substring(idx+1, property.length());
			if(this.properties.containsKey(sub))
					((EspecialProperties)this.properties.get(sub)).remove(prop);
		}
		return this;
	}
	
	public EspecialProperties clear(){
		this.properties.clear();
		return this;
	}
	
	@SuppressWarnings("unchecked")
	public Set<String> getProperties(){
		return (Set<String>)this.properties.get("this");
	}
	
	public boolean cotainsClazz(){
		Set<String> set = getProperties();
		return set != null && set.contains("clazz");
	}
	
	public EspecialProperties getEspecialProperties(String cla){
		if(!"this".equals(cla) && this.properties.containsKey(cla))
			return (EspecialProperties)this.properties.get(cla);
		return null;
	}
	
	public Set<String> getClazzes(){
		Set<String> res = null;
		if(this.properties != null){
			if(res == null)res = new HashSet<String>();
			for(String key:this.properties.keySet())
				if(!"this".equals(key))res.add(key);
		}
		return res;
	}
	
	public String[] getThisProperties(){
		Set<String> res = new HashSet<String>();
		Set<String> properties = getProperties(),classes = getClazzes();
		if(properties != null)res.addAll(properties);
		if(classes != null)res.addAll(classes);
		res.remove("clazz");
		return res.toArray(new String[0]);
	}
	
	public String toString(){
		Set<String> keys = getClazzes();
		if(keys != null){
			Iterator<String> itor = keys.iterator();
			String res = "|";
			while(itor.hasNext())res += itor.next() + "|";
			return res;
		}else return "null";
	}
	
	public String toSelfString(){
		Set<String> keys = getProperties();
		if(keys != null){
			Iterator<String> itor = keys.iterator();
			String res = "|";
			while(itor.hasNext())res += itor.next() + "|";
			return res;
		}else return "null";
	}
	
	public Class getClazz(){
		return this.clazz;
	}
	
	public void setElementClazz(Class cla){
		if(BaseReflector.isCollection(this.clazz))this.elementClazz = cla;
	}
	
	public boolean changeClazz(){
		if(BaseReflector.isCollection(this.elementClazz) ||
				(BaseReflector.isCollection(this.clazz) && this.elementClazz != null)){
			Class tmp = this.clazz;
			this.clazz = this.elementClazz;
			this.elementClazz = tmp;
			return true;
		}
		return false;
	}
	
}
